package com.ding.easycontroller.service.impl;

import com.ding.easycontroller.dao.WebSocketDao;
import com.ding.easycontroller.exception.CheckException;
import com.ding.easycontroller.service.WebSocketService;
import com.ding.easycontroller.utils.AntUtils;
import com.ding.easycontroller.utils.IdStrategy;
import com.ding.easycontroller.work.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.script.ScriptEngine;
import java.util.ArrayList;
import java.util.List;


@Service
public class WebSocketServiceImpl implements WebSocketService {


    @Autowired
    private WebSocketDao websocketDao;

    @Autowired
    private ScriptEngine scriptEngine;

    private List<WebSocket> websockets = new ArrayList<>();

    private WebSocket getByUri(String uri) {
        for (WebSocket socket : websockets) {
            if (socket.getUri().equals(uri)) {
                return socket;
            }
        }
        return null;
    }

    private void check(WebSocket websocket) {
        if (websocket.getUri().startsWith("/_config/")) {
            throw new RuntimeException("保留接口无法添加");
        }
        if (!websocket.getUri().startsWith("/")) {
            throw new RuntimeException("请求地址必须以/开始");
        }

        if (getByUri(websocket.getUri()) != null) {
            throw new RuntimeException("重复添加WebSocket:" + websocket.getUri());
        }
    }

    private void postHandle(WebSocket websocket) {
        String uri = websocket.getUri();
        char[] chars = uri.toCharArray();
        int n = 0;
        for (char aChar : chars) {
            if (aChar == '*') {
                n++;
            }
        }
        double rate = n * 1.0 / uri.length();
        if (websocket.getPathParams() != null) {
            rate += websocket.getPathParams().size() * 0.5 / uri.length();
        }

        websocket.setRate(rate);
    }

    private void initWebSocket(WebSocket websocket) {
        websocket.setScriptEngine(scriptEngine);
        try {
            websocket.init();
        } catch (Exception e) {
            throw new CheckException(e);
        }
    }

    private void tryAdd(WebSocket websocket) {
        preHandle(websocket);
        check(websocket);
        if (websocket.getId() == null) {
            websocket.setId(IdStrategy.createId(websocket));
        }
        sortAndAdd(websocket);
    }

    private void sortAndAdd(WebSocket websocket) {
        double rate = websocket.getRate();
        int i = 0;
        for (; i < websockets.size(); i++) {
            if (websockets.get(i).getRate() > rate) {
                break;
            }
        }
        websockets.add(i, websocket);
    }


    private void preHandle(WebSocket websocket) {

        //处理uri
        websocket.setUri(websocket.getUri().trim());

        //对路径进行变换
        String uri = websocket.getUri();
        if (uri.contains("*")) {
            websocket.setRegex(AntUtils.antPattern(uri));
        }

        //提取路径占位符
        String checkString = websocket.getRegex() == null ? websocket.getUri() : websocket.getRegex();
        if (checkString.contains("{")) {
            List<String> vs = new ArrayList<>();
            String s = AntUtils.pathVariables(checkString, vs);
            websocket.setRegexWithPathParams(s);
            websocket.setPathParams(vs);
        }
    }


    @Override
    public WebSocket matchesWebSocket(String uri) {

        for (WebSocket websocket : websocketDao.listAll()) {
            if (websocket.getRegexWithPathParams() != null) {
                if (uri.matches(websocket.getRegexWithPathParams())) {
                    return websocket;
                }
            } else if (websocket.getRegex() != null) {
                if (uri.matches(websocket.getRegex())) {
                    return websocket;
                }
            } else {
                if (uri.equals(websocket.getUri())) {
                    return websocket;
                }
            }
        }

        return null;
    }

    @Override
    public void removeById(String id) {
        WebSocket socket = getById(id);
        if (socket == null) {
            return;
        }
        socket.destroy();
        websockets.remove(socket);
        websocketDao.removeById(id);
    }

    @Override
    public void updateOrAdd(WebSocket websocket) {//由于更新可能修改请求方法所以需要删除websocket重新添加

        if (websocket.getId() != null) {
            WebSocket socket = getById(websocket.getId());

            if (socket == null) {
                throw new RuntimeException("不存在的websocket:" + websocket.getId());
            }
            tryUpdate(websocket, socket);
            websocketDao.update(websocket);
        } else {
            tryAdd(websocket);
            websocketDao.add(websocket);
        }

    }

    private void tryUpdate(WebSocket websocket, WebSocket old) {

        old.destroy();

        websockets.remove(old);

        try {
            websocket.setId(old.getId());
            tryAdd(websocket);
        } catch (Exception e) {
            old.init();
            websockets.add(old);
            throw e;
        }

    }


    @Override
    public WebSocket getById(String id) {
        for (WebSocket socket : websockets) {
            if (socket.getId().equals(id)) {
                return socket;
            }
        }
        return null;
    }

    @Override
    public List<WebSocket> listAll() {
        return websockets;
    }


    //恢复的过程中并没有进行排序运算,也没有处理
    @Override
    public void init() {
        List<WebSocket> all = websocketDao.listAll();
        for (WebSocket websocket : all) {
            try {
                tryAdd(websocket);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

